package main

import (
	"fmt"
	"unicode/utf8"
)

func main() {
	// s 是一个字符串，分配了一个代表泰语中“你好”一词的文字值。Go 字符串文字是 UTF-8 编码的文本。
	const s = "สวัสดี"

	// 因为字符串等同于 []byte，所以这将产生存储在其中的原始字节的长度。
	fmt.Println("Len:", len(s))

	// 在字符串中索引会产生每个索引处的原始字节值。这个循环生成构成 s 中代码点的所有字节的十六进制值。
	for i := 0; i < len(s); i++ {
		fmt.Printf("%x ", s[i])
	}
	fmt.Println()

	// 为了计算字符串中有多少个符文（runes），我们可以使用 utf8 包。请注意，RuneCountInString 的运行时取决于字符串的大小，因为它必须按顺序解码每个 UTF-8 符文。一些泰语字符由多个 UTF-8 代码点表示，因此此计数的结果可能令人惊讶。
	fmt.Println("Rune count:", utf8.RuneCountInString(s))

	// 范围循环对字符串进行特殊处理，并解码字符串中每个符文及其在字符串中的偏移量。
	for idx, runeValue := range s {
		fmt.Printf("%#U starts at %d\n", runeValue, idx)
	}

	// 我们可以通过显式使用 utf8.DecodeRuneInString 函数来实现相同的迭代。
	fmt.Println("\nUsing DecodeRuneInString")
	for i, w := 0, 0; i < len(s); i += w {
		runeValue, width := utf8.DecodeRuneInString(s[i:])
		fmt.Printf("%#U starts at %d\n", runeValue, i)
		w = width

		// 这演示了将符文值传递给函数。
		examineRune(runeValue)
	}
}

func examineRune(r rune) {
	// 用单引号括起来的值是符文文字。我们可以直接将符文值与符文文字进行比较。
	if r == 't' {
		fmt.Println("found tee")
	} else if r == 'ส' {
		fmt.Println("found so sua")
	}
}

/*
字符串是只读的字符序列： Go 中的字符串实际上是只读的字符序列，意味着一旦字符串被创建，
就不能直接修改它的内容。你可以访问字符串中的字符，但不能像数组一样直接修改。

UTF-8 编码： Go 中的字符串是以 UTF-8 编码的，这意味着它能够表示世界上几乎所有的字符。
UTF-8 是一种灵活的字符编码方式，使得在同一个字符串中可以包含多种语言的字符。

字符访问： 你可以通过索引来访问字符串中的单个字符，但需要注意的是，
由于 UTF-8 编码的关系，一个字符可能占用多个字节。因此，直接按照字节索引并不总是等同于字符的索引。

字符串拼接： Go 提供了简便的字符串拼接方式，使用 + 操作符可以将两个字符串连接在一起。
例如，"Hello" + " " + "World" 将得到新的字符串 "Hello World"。

字符串长度： 使用 len() 函数可以获取字符串中字符的个数。需要注意的是，len() 返回的是字符数，
而不是字节数。在 UTF-8 中，一个字符可能由一个或多个字节组成。

字符串比较： 使用 == 或 != 操作符可以比较两个字符串是否相等。这是按照字典顺序逐字符比较的。
*/

func f1() {
	str := "HelloWorld"
	// 试图修改字符串的某个字符，将会导致编译错误  因为string是只读的，我们不嫩修改它但是可以访问它
	// str[0] = 'h' // 无法分配给 str[0]
	val := str[0]
	fmt.Println(str)
	fmt.Println(val)
}

func f2() {
	//使用utf-8 可以表示多种字符
	str := "你好 世界"
	fmt.Println(str)
}

// 字符串拼接
func f3() {
	str1 := "Hello"
	str2 := "World"

	str3 := str1 + str2
	fmt.Println(str3)
}

// 字符串长度
func f4() {
	//len() 返回的是字符数，
	//而不是字节数。在 UTF-8 中，一个字符可能由一个或多个字节组成
	str := "HelloWorld"
	fmt.Println(len(str))
}

func f5() {
	str := "HelloWorld"
	fmt.Println(&str)
	str = str + "ok"
	fmt.Println(&str)
}
